package com.qdlc.p2p.dal.model.interest;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.qdlc.p2p.common.exception.BorrowException;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DateUtil;

/**
 * 等额本息利息计算函数
 *
 * @version 1.1.0.0
 * @author:wuaj
 */
public class InstallmentRepaymentCalculator implements InterestCalculator {

    /** 借款总额 */
    private double account;

    /** 年利率 */
    private double yearApr;

    /** 期数 */
    private int periods;

    /** 还款金额 */
    private double repayAccount;

    /** 利息管理费 */
    private double manageFee;

    /** 开始计息日 */
    private Date interestTime;

    /** 还款日 */
    private Date repayTime;

    /** 还款计划 */
    private List<EachPlan> eachPlanList;

    /**
     * 初始化等额本息构造函数
     *
     * @param account      借款总额
     * @param yearApr      年利率
     * @param interestTime 开始计息日
     * @param periods      期数
     * @param manageFee    利息管理费
     */
    public InstallmentRepaymentCalculator(double account, double yearApr, Date interestTime, int periods,
                                          double manageFee) {
        this.account = account;
        this.yearApr = yearApr;
        this.periods = periods;
        this.interestTime = interestTime;
        this.manageFee = manageFee;
        eachPlanList = new ArrayList<EachPlan>();
    }

    @Override
    public List<EachPlan> calculator() {
        // 每额本息
        double eachRepay = BigDecimalUtil.round(eachCapitalInterest(account, yearApr, periods), 2);
        // 总还款额
        double total = BigDecimalUtil.round(BigDecimalUtil.mul(eachRepay, periods), 2);
        // 剩余本息
        double remain = account;

        double totalInterest = 0;
        EachPlan eachPlan = null;
        // 开始计息日 + 1
        Date startInterestTime = DateUtil.rollDay(interestTime, 1);
        for (int i = 0; i < periods; i++) {
            eachPlan = new EachPlan();
            // 判断是否为最后一期,最后一期做减法
            double eachCapital;
            double eachInterest;
            if (i == periods - 1) {
                eachCapital = BigDecimalUtil.round(remain, 2); // 剩余本金
                // 利息 = 每月还款金额 - 本金
                eachInterest = BigDecimalUtil.round(BigDecimalUtil.sub(eachRepay, eachCapital), 2);
            } else {
                eachInterest = BigDecimalUtil.round(BigDecimalUtil.div(BigDecimalUtil.mul(remain, yearApr), 12)); // 每月 利息
                eachCapital = BigDecimalUtil.sub(eachRepay, eachInterest); // 每月 本金
            }
            totalInterest = BigDecimalUtil.add(totalInterest, eachInterest); // 累积利息

            // 净息
            double netInterest = BigDecimalUtil.round(BigDecimalUtil.mul(eachInterest, BigDecimalUtil.sub(1, manageFee)));

            eachPlan.setCapital(eachCapital);// 每期本金
            eachPlan.setInterest(eachInterest); // 每期利息
            eachPlan.setNetInterest(netInterest); // 每期净息

            eachPlan.setTotal(eachRepay); // 每期还款额(等额)
            eachPlan.setNetTotal(BigDecimalUtil.add(eachCapital, netInterest)); // 每期净还款额(等额)

            // 剩余本金
            remain = BigDecimalUtil.sub(remain, eachCapital);
            eachPlan.setNeedRepay(BigDecimalUtil.sub(total, BigDecimalUtil.mul(eachRepay, i + 1))); // 剩余还款本息

            eachPlan.setInterestTime(startInterestTime); // 计息开始时间
            eachPlan.setRepayTime(DateUtil.rollMon(startInterestTime, i + 1)); // 本期还款时间
            this.eachPlanList.add(eachPlan);
        }
        // 汇总信息
        this.repayAccount = total;
        this.repayTime = eachPlan.getRepayTime();
        return eachPlanList;
    }

    @Override
    public List<EachPlan> calculator(int days) {
        throw new BorrowException("等额本息不支持按天还款!", 1);
    }

    @Override
    public List<EachPlan> getEachPlanList() {
        return this.eachPlanList;
    }

    @Override
    public double repayTotal() {
        return this.repayAccount;
    }

    @Override
    public Date repayTime() {
        return this.repayTime;
    }

    @Override
    public Date calculatorRepayTime(Date date, int i) {
        return DateUtil.rollMon(date, i);
    }

    /**
     * 计算每一期等额的还款金额(等额)
     *
     * @param amount 借款总额
     * @param rate   年利率
     * @param month  期数
     * @return 每期还款金额
     */
    private double eachCapitalInterest(double amount, double rate, int month) {
        double mRate = BigDecimalUtil.div(rate, 12); // 月利率
        double aprPow = Math.pow(1 + mRate, month);
        double period = aprPow > 1 ? aprPow - 1 : 1;
        return BigDecimalUtil.div(BigDecimalUtil.mul(amount, mRate, aprPow), period);
    }
}
